package org.atlantis.net.nio;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Set;

public class TcpEchoServer {

	private static final int PORTS[] = new int[] { 6666, 8888 };
	private static final int TIMEOUT = 3000; // 等待超时

	public static void main(String[] args) throws Exception {
		Selector selector = Selector.open();
		// 可以绑定多个端口
		for (int port : PORTS) {
			ServerSocketChannel ssc = ServerSocketChannel.open();
			// 绑定端口
			ssc.socket().bind(new InetSocketAddress(port));
			// 设置为非阻塞
			ssc.configureBlocking(false);
			ssc.register(selector, SelectionKey.OP_ACCEPT);
		}

		ServerHandler handler = new ServerHandler(1024);

		// 一直循环来处理请求操作
		while (true) {
			/*
			 * select方法会阻塞，直到有准备好的I/O操作的通道。或者直到超时。 该方法将返回准备好的通道数。返回0则表示超时。
			 */
			if (selector.select(TIMEOUT) == 0) {
				continue;
			}
			// keys中包括了每个准备好某一IO操作的通道的SelectionKey（在注册时创建的）
			Set<SelectionKey> keys = selector.selectedKeys();
			for (SelectionKey key : keys) {
				if (key.isAcceptable()) handler.handleAccept(key);
				if (key.isReadable()) handler.handleRead(key);
				if (key.isWritable() && key.isValid()) handler.handleWrite(key);
				/*
				 * 由于select()操作只是向Selector所关联的键集合中添加元素，因此如果不移除处理过的键。
				 * 在下次迭代时仍然保修在集合中。
				 */
				keys.remove(key);
			}
		}
	}
}
